from wtforms import fields

from app.errors import ParameterError

from app.validators import BaseForm

from app.libs.enums import InspectionStrategySwitchStatus

# 枚举字段取值范围，见app.handler.v2_inspection中NUMBER_ENGINE_MAPPING和app.libs.enums.InspectionEventMarkerStatus
FIELD_NUMBER_RANGE_MAPPING = {
    "severity": [1, 2, 3, 4, 5],
    "markerStatus": [0, 1, 2, 3],
    "engine": [1, 2, 3, 4, 5, 6, 7],
    "eventType": [1, 2]
}


def string_form_enum_validator(field):
    data = field.data
    name = field.name
    if not data:
        return
    try:
        field_datas = [int(d.strip()) for d in data.split(",")]
        for field_data in field_datas:
            if field_data not in FIELD_NUMBER_RANGE_MAPPING.get(name, []):
                raise ParameterError(
                    f"enum number in field {name} must in range {FIELD_NUMBER_RANGE_MAPPING.get(name, [])}"
                )
    except ValueError:
        raise ParameterError(
            "field must be string, and enum number in field must be integer"
        )


class EventListForm(BaseForm):
    username = fields.StringField()
    url = fields.StringField()
    eventName = fields.StringField()
    eventId = fields.StringField(default="")
    severity = fields.StringField(default="")
    eventType = fields.IntegerField()
    taskSessionId = fields.StringField()
    markerStatus = fields.StringField(default="")
    engine = fields.StringField(default="")
    key = fields.StringField()
    start = fields.IntegerField()
    end = fields.IntegerField()
    page = fields.IntegerField(default=1)
    perPage = fields.IntegerField(default=10)
    riskUrl = fields.StringField()

    def validate_severity(self, value):
        string_form_enum_validator(value)

    def validate_eventId(self, value):
        if not value.data:
            return
        if len(value.data) != 32:
            raise ParameterError(msg="length of event id must be 32")

    def validate_markerStatus(self, value):
        string_form_enum_validator(value)

    def validate_engine(self, value):
        string_form_enum_validator(value)


class EventDetailForm(BaseForm):
    eventId = fields.StringField()

    def validate_eventId(self, value):
        if not value.data:
            raise ParameterError(msg="event id cannot be null")
        if len(value.data) != 32:
            raise ParameterError(msg="length of event id must be 32")


class EventMarkForm(BaseForm):
    eventIds = fields.FieldList(fields.StringField())

    markerStatus = fields.IntegerField()
    remarks = fields.StringField()
    supportingImages = fields.FieldList(fields.StringField())

    def validate_eventIds(self, value):
        if not value.data:
            raise ParameterError(msg="requires at least one event id")
        for event_id in value.data:
            if len(event_id) < 32:
                raise ParameterError(msg="length of event id must be 32")

    def validate_markerStatus(self, value):
        if not value.data:
            raise ParameterError(msg="marker status cannot be null")
        if value.data not in range(1, 5):
            raise ParameterError(msg="marker status must be in 1~4")


class IgnoreStrategyListForm(BaseForm):
    page = fields.IntegerField(default=1)
    perPage = fields.IntegerField(default=10)
    key = fields.StringField()
    url = fields.StringField()


class IgnoreStrategyAddForm(BaseForm):
    key = fields.StringField()
    url = fields.StringField()
    remarks = fields.StringField()


class IgnoreStrategyModifyForm(BaseForm):
    strategyId = fields.StringField()
    key = fields.StringField()
    url = fields.StringField()
    remarks = fields.StringField()
    switchStatus = fields.IntegerField()

    def validate_strategyId(self, value):
        if not value.data:
            raise ParameterError(msg="strategy id cannot be null")
        if len(value.data) != 24:
            raise ParameterError(msg="length of strategy id must be 24")

    def validate_switchStatus(self, value):
        if value.data not in [InspectionStrategySwitchStatus.OPEN.value, InspectionStrategySwitchStatus.CLOSE.value]:
            raise ParameterError(msg="switch status must in [0, 1]")


class IgnoreStrategyDeleteForm(BaseForm):
    strategyId = fields.StringField()

    def validate_strategyId(self, value):
        if not value.data:
            raise ParameterError(msg="strategy id cannot be null")
        if len(value.data) != 24:
            raise ParameterError(msg="length of strategy id must be 24")
